package com.topisv.tms.service.work.prepkg;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.hibernate.ejb.criteria.predicate.ComparisonPredicate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.dto.CommonDto;
import com.topisv.tms.entity.stock.CusStock;
import com.topisv.tms.entity.work.prepkg.PrepkgPickItem;
import com.topisv.tms.entity.work.prepkg.PrepkgPickTask;
import com.topisv.tms.entity.work.prepkg.PrepkgPlan;
import com.topisv.tms.repository.stock.CusStockDao;
import com.topisv.tms.repository.work.prepkg.PrepkgPickItemDao;
import com.topisv.tms.repository.work.prepkg.PrepkgPickTaskDao;
import com.topisv.tms.repository.work.prepkg.PrepkgPlanDao;
import com.topisv.tms.service.account.ShiroDbRealm.ShiroUser;
import com.topisv.tms.utils.rule.TMSTransportRule;

/**
 * 预包装计划_service
 * @author ch
 */
@Component
@Transactional(readOnly = true)
public class PrepkgPlanService {

	@Autowired
	private PrepkgPlanDao prepkgPlanDao;
	@Autowired
	private CusStockDao cusStockDao;
	@Autowired
	private PrepkgPickTaskDao prepkgPickTaskDao;
	@Autowired
	private PrepkgPickItemDao prepkgPickItemDao;

	/**
	 * 创建预包装计划
	 * @param customerCode
	 * @param warehouseCode
	 * @param infoMap
	 * @return
	 * @throws Exception 
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public String createPlan(String customerCode, String warehouseCode,Map<String, Integer> infoMap) throws Exception {
		
		try {
			
			List<CommonDto> pickInfoList=new ArrayList<CommonDto>();
			String errorList="";
			int goodsNum=0;
			int skuNum=0;
			
			for(String sku:infoMap.keySet()){
				
				int sku_num = infoMap.get(sku); // 每个sku需求数量
				goodsNum+=sku_num; //商品数量合计
				skuNum++; //sku数量合计
				List<CusStock> stockList = this.cusStockDao.loadStock(warehouseCode, customerCode, sku);
				
				
				// 排序：库存数量升序排列，
				Collections.sort(stockList, new Comparator<CusStock>() {
					public int compare(CusStock o1, CusStock o2) {
						return o1.getSalesNum().compareTo(o2.getSalesNum());
					}
				});
				
				boolean flag = false;
				// 找到最接近满足的箱位
				for (CusStock cusStock : stockList) {
					if (cusStock.getSalesNum() >= sku_num) { 
						CommonDto dto=new CommonDto();
						dto.setField1(sku);
						dto.setField2(cusStock.getStockCode());
						dto.setField3(cusStock.getBoxCode());
						dto.setField4(sku_num);
						pickInfoList.add(dto);
						sku_num=0;
						flag = true;
						break;
					}
				}
				
				// 如果没有找到最接近的箱位，箱位组合分配。
				if (!flag) {
					Collections.reverse(stockList); // 排序，商品数量降序
					for (CusStock cusStock : stockList) {
						
						if (sku_num == 0){
							break;
						}
						
						int salesNum=cusStock.getSalesNum();
						if(salesNum<=sku_num){
							sku_num=sku_num-salesNum;
							CommonDto dto=new CommonDto();
							dto.setField1(sku);
							dto.setField2(cusStock.getStockCode());
							dto.setField3(cusStock.getBoxCode());
							dto.setField4(salesNum);
							pickInfoList.add(dto);
							
						}else if(salesNum>sku_num){
							sku_num=0;
							CommonDto dto=new CommonDto();
							dto.setField1(sku);
							dto.setField2(cusStock.getStockCode());
							dto.setField3(cusStock.getBoxCode());
							dto.setField4(sku_num);
							pickInfoList.add(dto);
							
						}
						
					}
					
				}
				
				if(sku_num>0){
					if(errorList.length()>0){
						errorList+=",";
					}
					errorList+=sku;
				}
			}
			
			//如果有商品不能满足库存，返回
			if(errorList.length()>0){
				return errorList;
			}
			
			
			Date now=new Date();
			ShiroUser curUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
			
			//创建预包装计划
			PrepkgPlan plan=new PrepkgPlan();
			plan.setCreaterUuid(curUser.jobuuid);
			plan.setCreateTime(now);
			plan.setCustomerCode(customerCode);
			plan.setGoodsNum(goodsNum);
			plan.setPlanCode(TMSTransportRule.generatePrePlanCode());
			plan.setSkuNum(skuNum);
			plan.setStatus("create");
			plan.setWarehouseCode(warehouseCode);
			this.prepkgPlanDao.save(plan);
			
			//创建拣货任务
			PrepkgPickTask pickTask=new PrepkgPickTask();
			pickTask.setCreateTime(now);
			pickTask.setCustomerCode(customerCode);
			pickTask.setPlanCode(plan.getPlanCode());
			pickTask.setStatus("undo"); //任务状态 （undo.创建拣货任务 token:领取任务 doing:拣货中 finish.拣货完成）
			pickTask.setTaskCode(TMSTransportRule.generatePrePickTaskCode());
			pickTask.setWarehouseCode(warehouseCode);
			pickTask.setSkuNum(skuNum);
			pickTask.setGoodsNum(goodsNum);
			this.prepkgPickTaskDao.save(pickTask);
			
			//修改库存信息、创建拣货任务明细
			for (CommonDto dto : pickInfoList) {
				String sku=(String) dto.getField1();
				String stockCode=(String) dto.getField2();
				String boxCode=(String) dto.getField3();
				Integer num=(Integer) dto.getField4();
				
				//修改库存信息
				CusStock stock=this.cusStockDao.loadStock(customerCode, warehouseCode, stockCode, boxCode, sku);
				stock.setSalesNum(stock.getSalesNum()-num);
				stock.setOrderNum(stock.getOrderNum()+num);
				this.cusStockDao.save(stock);
				
				//创建拣货任务明细
				PrepkgPickItem  pickItem=new PrepkgPickItem();
				pickItem.setBoxCode(boxCode);
				pickItem.setCustomerCode(customerCode);
				pickItem.setNum(num);
				pickItem.setPlanCode(plan.getPlanCode());
				pickItem.setSku(sku);
				pickItem.setStatus("unpicked");
				pickItem.setStockCode(stockCode);
				pickItem.setTaskCode(pickTask.getTaskCode());
				pickItem.setWarehouseCode(warehouseCode);
				this.prepkgPickItemDao.save(pickItem);
			}
			
			return errorList;
			
		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * 分页查询
	 * @param param
	 * @param pageNumber
	 * @param pageSize
	 * @return
	 */
	public Page<PrepkgPlan> loadByParam(Map<String, Object> param, int pageNumber,int pageSize) {
		Sort sort = new Sort(Sort.Direction.DESC,"id");
	    PageRequest pageRequest = new PageRequest(pageNumber-1, pageSize, sort);
	    Specification<PrepkgPlan> spec =this.getWhereClause(param);
	    Page<PrepkgPlan> page = this.prepkgPlanDao.findAll(spec, pageRequest);
	    return page;
	}
	
	
	/**
	 * 条件封装
	 * @param param
	 * @return
	 */
	private Specification<PrepkgPlan> getWhereClause(final Map<String, Object> param) {
		 return new Specification<PrepkgPlan>(){
		    @Override
		    public Predicate toPredicate(Root<PrepkgPlan> r, CriteriaQuery<?> q, CriteriaBuilder cb) {
		      Predicate pre = cb.conjunction();
		      
		     //customerCodes
		     String customerCodes=(String) param.get("customerCodes");
		     if(StringUtils.isNotBlank(customerCodes)) {
		    	  String[] customerCodeSplit = customerCodes.split(":");
				  ComparisonPredicate[] tempCustomerCode = new ComparisonPredicate[customerCodeSplit.length];
				  int i = 0;
				  for (String _customerCode : customerCodeSplit) {
					 tempCustomerCode[i] = (ComparisonPredicate) cb.equal(r.get("customerCode"), _customerCode);
					 i++;
				  }
				  pre.getExpressions().add(cb.or(tempCustomerCode));
		      }
		     
		      //customerCode
		      String customerCode=(String) param.get("customerCode");
		      if(StringUtils.isNotBlank(customerCode)){
		         pre.getExpressions().add(cb.like(r.<String>get("customerCode"),customerCode));
			  }
		      
		      //warehouseCode
		      String warehouseCode=(String) param.get("warehouseCode");
		      if(StringUtils.isNotBlank(warehouseCode)){
		         pre.getExpressions().add(cb.like(r.<String>get("warehouseCode"),warehouseCode));
			  }
		      
		      //planCode
		      String planCode=(String) param.get("planCode");
		      if(StringUtils.isNotBlank(planCode)){
		         pre.getExpressions().add(cb.like(r.<String>get("planCode"),"%"+planCode+"%"));
			  }
		      
		      //status
		      String status=(String) param.get("status");
		      if(StringUtils.isNotBlank(status)){
		         pre.getExpressions().add(cb.like(r.<String>get("status"),status));
			  }
		      
		      //创建时间
		      Date fromDate= (Date) param.get("fromDate");
		      if (fromDate != null) {
		        pre.getExpressions().add(cb.greaterThanOrEqualTo(r.<Date>get("createTime"), fromDate));
		      }
		      
		      Date toDate= (Date) param.get("toDate");
		      if (toDate != null) {
		        pre.getExpressions().add(cb.lessThanOrEqualTo(r.<Date>get("createTime"), toDate));
		      }
		      
		      return pre;
		    }
		  };
	}

}